import { ref, onBeforeUnmount } from "vue";
import * as monaco from "monaco-editor/esm/vs/editor/editor.api";
import nunjucks from "nunjucks";
import { pickBy, omit } from "lodash-es";
import type { ComponentType, AnyObject } from "@/materials/index.d";
import * as prettier from "prettier/standalone";
import prettierPluginBabel from "prettier/plugins/babel";
import prettierPluginEstree from "prettier/plugins/estree";
import prettierPluginHtml from "prettier/plugins/html";

// hooks 函数: 使用 CodeEditor
export const useCodeEditor = (
  options: monaco.editor.IStandaloneEditorConstructionOptions = {}
) => {
  // 获取DOM元素，编辑器渲染的DOM元素
  const el = ref();

  let editor: monaco.editor.IStandaloneCodeEditor;

  // 创建编辑器的方法
  const createEditor = () => {
    editor = monaco.editor.create(el.value, {
      // https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html
      language: "typescript",
      automaticLayout: true, // 自动布局
      // readOnly: true, // 只读
      minimap: { enabled: false }, // 隐藏代码缩略图
      ...options, // 其他配置项
    });

    return editor;
  };

  // 更新编辑器的值（显示代码）
  const updateEditorValue = async (value: string) => {
    editor.setValue(value);
  };

  // 获取编辑器的值
  const getEditorValue = () => {
    return editor.getValue();
  };

  // 卸载时，清除编辑器的内容
  onBeforeUnmount(() => {
    // 关闭编辑器
    editor.dispose();
  });

  return {
    el,
    createEditor,
    updateEditorValue,
    getEditorValue,
  };
};

// hooks 函数: 将 config 变成代码（格式化）
export const useCompileCode = () => {
  const tplItem = `<{{ package }} 
{% for key, value in filterEmpty(omitProps(props)) %}
  {{ addColon(value) }}{{ key }}="{{ value }}"
{% endfor %}

:style="{
  {% for key, value in filterEmpty(styles) %}
    {{ key }}: '{{ value }}',
  {% endfor %}
}"
>
  {{ props.slot }}
</{{ package }}>`;

  const tplList = `<template>
  {% for component in componentList %}
    <{{ component.package }} 
    {% for key, value in filterEmpty(omitProps(component.props)) %}
      {{ addColon(value) }}{{ key }}="{{ value }}"
    {% endfor %}
    :style="{
      {% for key, value in filterEmpty(component.styles) %}
        {{ key }}: '{{ value }}',
      {% endfor %}
    }"
    >
      {{ component.props.slot }}
    </{{ component.package }}>
  {% endfor %}
</template>
<script lang="ts" setup>
  {% for component in componentList %}import {{ component.package }} from '@/components/{{ component.package }}/index.vue';
  {% endfor %}
</script>`;

  // 添加冒号
  const addColon = (val: any) => {
    return typeof val === "string" ? "" : ":";
  };
  // 过滤空数据
  const filterEmpty = (data: AnyObject) => {
    return pickBy(data, (value) => value !== "");
  };
  // 排除属性
  const omitProps = (data: AnyObject) => {
    return omit(data, ["slot"]);
  };

  // 1. 使用模板引擎将字符串+数据编译成代码
  const renderString = (data: ComponentType) => {
    return nunjucks.renderString(tplItem, {
      ...data,
      addColon,
      filterEmpty,
      omitProps,
    });
  };

  const renderListString = (data: ComponentType) => {
    return nunjucks.renderString(tplList, {
      ...data,
      addColon,
      filterEmpty,
      omitProps,
    });
  };
  // 2. 使用prettier格式化代码
  const formatCode = (code: string) => {
    return prettier.format(code, {
      parser: "vue",
      plugins: [prettierPluginBabel, prettierPluginEstree, prettierPluginHtml],
    });
  };

  // 编译代码
  const compileCode = (data: ComponentType, type = "item") => {
    const render = type === "item" ? renderString : renderListString;
    const code = render(data);
    return formatCode(code);
  };

  return {
    compileCode,
  };
};

export type EditorOptions = monaco.editor.IStandaloneEditorConstructionOptions;
